package com.test.learnkotlin

import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch

/*
    kotlin高阶函数部分场景示例
    https://blog.csdn.net/u013347784/article/details/122165061

    Kotlin学习笔记——（八）高阶函数案例
    https://blog.csdn.net/miyuexingchen/article/details/121295743

    【kotlin】高阶函数详解
    https://blog.csdn.net/u010356768/article/details/108490612?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-108490612-blog-121295743.t0_eslanding_v1&spm=1001.2101.3001.4242.1&utm_relevant_index=3


    Kotlin高阶函数实战
    https://www.bbsmax.com/A/gAJGNY10zZ/

 */

/*

普通 show
普通函数返回结果 :普通 OK
高阶函数 show2
高阶函数返回结果：高阶1 OK
高阶函数 show2
高阶函数返回结果：高阶2 OK
高阶函数 show2
高阶函数返回结果：高阶3 OK
高阶函数 show2
高阶函数返回结果：高阶4 OK
name = 测试 , token = 4geh3643t
loginResult = 登录结果
kouniqiwa
hi
1230
i love you baby
测试
测试2
测试2
没有监听器
Hi
What Do I Call You
Destiny
century ago
测试
测试函数引用


 */
fun main() {
    show(true, object : KtCallback {
        override fun show(info: String): String {
            println(info)
            return "普通 OK"
        }
    })

    //外界调用，四种写法均可
    show2(true, callback = {
        println(it)
        "高阶1 OK"
    })

    show2(true, {
        println(it)
        "高阶2 OK"
    })

    show2(true, { info: String ->
        println(info)
        "高阶3 OK"
    })

    show2(true) {
        println(it)
        "高阶4 OK"
    }

    login("root", "123456") { msg, code, loginbean ->

        if (code == 200) {
            if (loginbean != null) {

            }
        }

    }

    val loginBean = LoginBean("测试", "4geh3643t")
    val loginResult = loginBean.work {
        println("name = $name , token = $token")
        "登录结果"
    }

    println("loginResult = $loginResult")
    //name = 测试 , token = 4geh3643t
    //loginResult = 登录结果

    println("kouniqiwa".work {
        println(this)
        "hi"
    })

    println(123.work { this.times(10) })

    println("I LOVE YOU BABY".work { lowercase() })


    show("测试", func = { println(it) })
    show("测试2", { println(it) })
    show("测试2") { println(it) }


    //模仿监听
    val listener = ListenerOp<String>()
    listener.action()
    listener.setListener("Hi") { println(it) }
    listener.setListener("What Do I Call You") { println(it) }
    listener.setListener("Destiny") { println(it) }


    listener.setListener("century ago", ::funcRef)

    listener.setListener("测试", ::console)
    val r = ::console
    listener.setListener("测试函数引用", r)

    listener.action()

    //没有监听器
    //Hi
    //What Do I Call You
    //Destiny
    //century ago
    //测试
    //测试函数引用


}

fun console(str: String) = println(str)

fun <T> funcRef(t: T) {
    println(t)
}

/*
函数作为形参传入函数

需求：写一个方法名为“show”的函数，有两个入参，参数1是个boolean类型，参数2是一个回调函数，返回一个String类型的值

首先咱们先看下不用高阶怎么实现：

第一步：定义一个回调接口函数

 */

interface KtCallback {
    fun show(info: String): String
}

interface KtCallback2 {
    fun show2(info: String): String
    fun show2(info: String, isShowLong: Boolean): String
}

fun show(isShow: Boolean, callback: KtCallback) {
    if (isShow) {
        val result = callback.show("普通 show")
        println("普通函数返回结果 :$result")
    }
}

/*
用高阶函数来实现这个需求
直接写出此函数
 */
fun show2(isShow: Boolean, callback: (String) -> String) {
    if (isShow) {
        val result = callback("高阶函数 show2")
        println("高阶函数返回结果：$result")
    }
}

fun show3(isShow: Boolean, callback2: (String, Boolean) -> String) {
    if (isShow) {
        val result2 = callback2("高阶函数 show2", false)
        println("高阶函数返回结果：$result2")
    }
}

//高阶函数使用案例
data class LoginBean(val name: String, val token: String)

fun login(name: String, pwd: String, response: (String, Int, LoginBean?) -> Unit) {
    if ("root" == name && "123456" == pwd) {
        response("登录成功", 200, LoginBean(name, "4154365greagary5yrfvwgwg"))
    } else {
        response("用户名或密码错误", 400, null)
    }
}

//高阶函数配合扩展函数使用
fun <T, R> T.work(action: T.() -> R) = action()

//函数作为最后一个参数的调用方式
fun show(msg: String, func: (String) -> Unit) = func(msg)

//模仿监听
class ListenerOp<T> {
    val actions = ArrayList<(T) -> Unit>()
    val values = ArrayList<(T)>()

    fun action() {
        if (actions.isEmpty()) {
            println("没有监听器")
        } else {
            actions.forEachIndexed { index, function ->
                function(values[index])
            }
        }
    }

    fun setListener(value: T, action: (T) -> Unit) {
        values += value
        actions += action
    }

}

/*
Android实现倒计时的6种方案汇总
https://mp.weixin.qq.com/s/5BENEushP6Yjoae5gvDX0w
 */
fun FragmentActivity.countDown(
    time: Int = 5,
    start: (scop: CoroutineScope) -> Unit,
    end: () -> Unit,
    next: (time: Int) -> Unit
) {
    lifecycleScope.launch {
        // 在这个范围内启动的协程会在Lifecycle被销毁的时候自动取消
        flow<Int> {
            (time downTo 0).forEach {
                delay(1000)
                emit(it)
            }
        }.onStart {
            // 倒计时开始 ，在这里可以让Button 禁止点击状态
            start(this@launch)
        }.onCompletion {
            // 倒计时结束 ，在这里可以让Button 恢复点击状态
            end()
        }.catch {
            //错误
            println(it.message ?: "未知错误")
        }.collect {
            //在这里 更新值来显示到UI
            next(it)
        }

    }

}
